package org.dromara.wms.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.web.core.BaseService;
import org.dromara.sms4j.starter.utils.SpringUtil;
import org.dromara.wms.domain.*;
import org.dromara.wms.mapper.WmsOrderLineMapper;
import org.dromara.wms.mapper.WmsTaskBomMapper;
import org.dromara.wms.mapper.WmsTaskProcessMapper;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.dromara.wms.mapper.WmsTaskMapper;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 生产工单Service业务层处理
 *
 * @author wenrui Su
 * @date 2024-05-05
 */
@RequiredArgsConstructor
@Service
public class WmsTaskService extends BaseService {

    private final WmsTaskMapper baseMapper;
    private final WmsBomServiceImpl wmsBomService;
    private final WmsOrderServiceImpl wmsOrderService;
    private final WmsProductServiceImpl wmsProductService;
    private final WmsStockService wmsStockService;
    private final WmsWorkshopService wmsWorkshopService;
    private final WmsStockLogService stockLogService;
    private final WmsTaskBomMapper wmsTaskBomMapper;
    private final WmsTaskProcessMapper wmsTaskProcessMapper;
    private final WmsOrderLineMapper orderLineMapper;

  public WmsScheduleLineService scheduleLineService() {
    return SpringUtil.getBean(WmsScheduleLineService.class);
  }

    /**
     * 查询生产工单
     */
    public WmsTask queryById(Long id){
        return baseMapper.selectById(id);
    }

    /**
     * 查询生产工单列表
     */
    public TableDataInfo<WmsTask> queryPageList(WmsTask bo, PageQuery pageQuery) {
        Page<WmsTask> result = baseMapper.getWmsTaskList(pageQuery.build(), bo);
        return TableDataInfo.build(result);
    }

    /**
     * 查询生产工单列表
     */
    public List<WmsTask> queryList(WmsTask bo) {
        LambdaQueryWrapper<WmsTask> lqw = buildQueryWrapper(bo);
        return baseMapper.selectList(lqw);
    }

    /**
     * 查询生产工单列表
     */
    public WmsTask querySort() {
      QueryWrapper<WmsTask> queryWrapper = new QueryWrapper<>();
      queryWrapper.select("max(sort)");
      return baseMapper.selectOne(queryWrapper );
    }

    private LambdaQueryWrapper<WmsTask> buildQueryWrapper(WmsTask bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<WmsTask> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getTaskName()), WmsTask::getTaskName, bo.getTaskName());
        lqw.eq(bo.getScheduleLineId() != null, WmsTask::getScheduleLineId, bo.getScheduleLineId());
        lqw.eq(bo.getProductId() != null, WmsTask::getProductId, bo.getProductId());
        lqw.eq(StringUtils.isNotBlank(bo.getBatchCode()), WmsTask::getBatchCode, bo.getBatchCode());
        lqw.eq(bo.getStartTime() != null, WmsTask::getStartTime, bo.getStartTime());
        lqw.eq(bo.getEndTime() != null, WmsTask::getEndTime, bo.getEndTime());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), WmsTask::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增生产工单
     */
    public Boolean insertByBo(WmsTask bo) {
        validEntityBeforeSave(bo);
        boolean flag = baseMapper.insert(bo) > 0;
        return flag;
    }

    /**
     * 修改生产工单
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = WmsStockService.emptyException.class)
    public R<Void> updateByBo(WmsTask bo) throws WmsStockService.emptyException {
        validEntityBeforeSave(bo);
        switch (bo.getStatus()){
          case "1":
            //新开转派工
            //获取所在生产线仓库id
            Long wmId = getWmId(bo);
            //获取所需物料清单
            List<WmsBomLine> BottomMaterial = getBomList(bo);
            //生成物料计划单
            wmsOrderVo(BottomMaterial, bo,30L, " 物料计划单", wmId);
            break;
          case "2":
            //派工转上线
            // 扣除物品的材料库存数量
            //根据当前的task id,从物料计划订单获取所需物料数目
            WmsOrder wmsOrder2 = new WmsOrder();
            wmsOrder2.setSourceId(bo.getId());
            wmsOrder2.setTypeId(30L);
            List<WmsOrder> wmsOrdersList = wmsOrderService.queryList(wmsOrder2);
            List<WmsTaskBom> wmsTaskBomList = new ArrayList<>();
            if (!wmsOrdersList.isEmpty()){
              //根据bo.scheduleLineId，获取batchCode
              WmsScheduleLine scheduleLine = scheduleLineService().queryById(bo.getScheduleLineId());
              //查询对应orderLine
              WmsOrderLine lineBo = new WmsOrderLine();
              lineBo.setId(wmsOrdersList.get(0).getId());
              List<WmsOrderLine> orderLines = orderLineMapper.queryLinePageList(lineBo);
              for (WmsOrderLine orderLine : orderLines) {
                //更新库存
                WmsStock wmsStock2 = getWmsStock(orderLine);
                List<WmsTaskBom> wmsTaskBomListRes = wmsStockService.stockOut(wmsStock2,wmsOrdersList.get(0),scheduleLine.getBatchCode());
                wmsTaskBomList.addAll(wmsTaskBomListRes);
              }
            }else{
              throw new WmsStockService.emptyException("未查找到该工单的物料计划单，请核对后重试");
            }
            //生成wms_task_bom的数据
            //获取所需物料清单
            List<WmsBomLine> BottomMaterial2 = getBomList(bo);
            Collection<WmsTaskBom> wmsTaskBomListIns = new ArrayList<>();
            for (WmsTaskBom wmsTaskBomListRe : wmsTaskBomList) {
              WmsTaskBom wmsTaskBom = getWmsTaskBom(bo, wmsTaskBomListRe, BottomMaterial2);
              wmsTaskBomListIns.add(wmsTaskBom);
            }
            wmsTaskBomMapper.insertBatch(wmsTaskBomListIns);

            //生成wms_task_process的数据
            //获取工序列表
            List<WmsBomProcess> bomProcessList = wmsBomService.selectById(bo.getBomId());
            Collection<WmsTaskProcess> wmsTaskProcesses = new ArrayList<>();
            for (WmsBomProcess bomProcess : bomProcessList) {
              WmsTaskProcess wmsTaskProcess = new WmsTaskProcess();
              wmsTaskProcess.setTaskId(bo.getId());
              wmsTaskProcess.setProcessId(bomProcess.getLineId());
              wmsTaskProcess.setStatus(bomProcess.getStatus());
              wmsTaskProcess.setOperId(bo.getUpdateBy());
              wmsTaskProcess.setOperTime(bo.getUpdateTime());
              wmsTaskProcesses.add(wmsTaskProcess);
            }
            wmsTaskProcessMapper.insertBatch(wmsTaskProcesses);

            break;
          case "3":
            // 从工单上线转变为，返工状态，进入维修区
            break;
          case "4":
            // 从工单生产和返工状态，编程完工状态，工单完工，
            // 计划排程表更新数量和状态
            WmsScheduleLine scheduleLineRes = scheduleLineService().queryById(bo.getScheduleLineId());
            PageQuery pageQuery = new PageQuery();
            TableDataInfo<WmsScheduleLine> res = scheduleLineService().queryPageList(scheduleLineRes, pageQuery);
            List<WmsScheduleLine> resData = res.getRows();
            if (resData.isEmpty()){
              throw new WmsStockService.emptyException("未查找到该工单的计划排程单，请核对后重试");
            }
            Double num = bo.getQuantity();
            if (resData.get(0).getTotalQuantityFinished() != null){
              num += resData.get(0).getTotalQuantityFinished();
            }
            if (resData.get(0).getQuantity() - num == 0){
              WmsScheduleLine wmsScheduleLine = new WmsScheduleLine();
              wmsScheduleLine.setLineId(bo.getScheduleLineId());
              wmsScheduleLine.setStatus("2");
              scheduleLineService().updateByBo(wmsScheduleLine);
            }
            break;
          case "5":
            Long wmId5 = getWmId(bo);

            // 成品入库
            WmsStock wmsStock = new WmsStock();
            wmsStock.setProductId(bo.getProductId());
            wmsStock.setWarehouseId(301L);//生产边库
            wmsStock.setMeasureUnit(wmsProductService.queryById(bo.getProductId()).getMeasureUnit());
            wmsStock.setQuantity(scheduleLineService().queryById(bo.getScheduleLineId()).getQuantity());
            wmsStock.setBatchCode(bo.getBatchCode());

            //库存日志-插入前查询库存数量
            WmsStockLog stockLog = new WmsStockLog();
            List<WmsStock> stockList = wmsStockService.selectList(wmsStock);
            double totalQuantity = stockList.stream()
              .mapToDouble(WmsStock::getQuantity)
              .sum();
            stockLog.setQuantityBefore(totalQuantity);
            stockLog.setQuantityAfter(totalQuantity + wmsStock.getQuantity());

            wmsStockService.stockIn(wmsStock);

            //库存日志
            stockLog.setProductId(wmsStock.getProductId());
            stockLog.setMeasureUnit(wmsStock.getMeasureUnit());
            stockLog.setBatchCode(wmsStock.getBatchCode());
            stockLog.setOrderId(wmsStock.getId());
            stockLog.setTypeId(40L);
            stockLog.setWarehouseId(wmsStock.getWarehouseId());
            stockLogService.insertByBo(stockLog);

            // 根据工单的bom和库存，生成物料采购计划单，填补耗材
            //获取所需物料清单
            List<WmsBomLine> BottomMaterial5 = getBomList(bo);
            wmsOrderVo(BottomMaterial5, bo,21L, " 物耗采购计划单", wmId5);
            break;
          default: break;
        }
        return toAjax(baseMapper.updateById(bo) > 0);
    }

  @NotNull
  private static WmsTaskBom getWmsTaskBom(WmsTask bo, WmsTaskBom wmsTaskBomListRe, List<WmsBomLine> BottomMaterial2) {
    WmsTaskBom wmsTaskBom = new WmsTaskBom();
    wmsTaskBom.setTaskId(bo.getId());
    wmsTaskBom.setBatchCode(wmsTaskBomListRe.getBatchCode());
    wmsTaskBom.setProductId(wmsTaskBomListRe.getProductId());
    for (WmsBomLine wmsBomLine : BottomMaterial2) {
      if (Objects.equals(wmsBomLine.getProductId(), wmsTaskBom.getProductId())){
        wmsTaskBom.setStatus(wmsBomLine.getStatus());
        break;
      }
    }
    wmsTaskBom.setOperId(bo.getUpdateBy());
    wmsTaskBom.setOperTime(bo.getUpdateTime());
    return wmsTaskBom;
  }

  @NotNull
  private static WmsStock getWmsStock(WmsOrderLine orderLine) {
    WmsStock stockCheckLine = new WmsStock();
    stockCheckLine.setProductId(orderLine.getProductId());
    stockCheckLine.setWarehouseId(orderLine.getWhId());
    stockCheckLine.setMeasureUnit(orderLine.getMeasureUnit());
    stockCheckLine.setQuantity(orderLine.getQuantity());
    stockCheckLine.setProductName(orderLine.getProductName());
    stockCheckLine.setWareName(orderLine.getWhName());
    stockCheckLine.setBatchCode(orderLine.getBatchCode());
    return stockCheckLine;
  }

  public List<WmsBomLine> getBomList(WmsTask bo){
      //二、获取所需物料清单
      //（2）排程信息获取bomId查找bom信息，然后获取bomLine，得到物料清单
      WmsScheduleLine scheduleLine = scheduleLineService().queryById(bo.getScheduleLineId());
      WmsBom wmsBom = wmsBomService.queryById(scheduleLine.getBomId());
      WmsBomLine wmsBomLine = new WmsBomLine();
      wmsBomLine.setId(wmsBom.getId());
      List<WmsBomLine> wmsBomLineList = wmsBomService.queryLineList(wmsBomLine);
      //wmId：生产线对应仓库id,wmsBomLineList：所需物料清单，然后根据仓库id和物料清单，检查当前库存是否足够
      //（1）物料清单需要判断最底层物料所需数量
      // ① 取出底层物料并计算好底层物料所需的数量
        return getBottomMaterial(wmsBomLineList , bo.getQuantity());
    }

    //计算所有底层物料所需数量，排出底层物料以外的其他物料
    private List<WmsBomLine> getBottomMaterial(List<WmsBomLine> wmsBomLineList, Double quantity){
      List<WmsBomLine> requestList = new ArrayList<>(wmsBomLineList);
      for( WmsBomLine item : wmsBomLineList){
        for( WmsBomLine item2 : wmsBomLineList) {
          //更新底层物料所需数量
          if (Objects.equals(item.getProductId(), item2.getParentId())) {
            item2.setQuantity(String.valueOf(Double.parseDouble(item.getQuantity()) * Double.parseDouble(item2.getQuantity())));
            requestList.remove(item);
          }
        }
        item.setQuantity(String.valueOf(Double.parseDouble(item.getQuantity()) * quantity));
      }
      return requestList;
    }

    //生成物料计划单和物耗采购单
    private void wmsOrderVo(List<WmsBomLine> bomList, WmsTask bo, Long orderType, String orderName, Long wmId) throws WmsStockService.emptyException {
      WmsBomLine wmsBomLine = new WmsBomLine();
      wmsBomLine.setId(bo.getBomId());
//      //获取物料清单bomList
//      List<WmsBomLine> bomList = wmsBomService.queryLineList(wmsBomLine);
      WmsOrder wmsOrder = new WmsOrder();
      wmsOrder.setName("工单"+orderName);
      wmsOrder.setTypeId(orderType);
      wmsOrder.setSelfWhId(wmId);
      wmsOrder.setStatus("1");
      wmsOrder.setSourceId(bo.getId());
      wmsOrder.setRemark( "计划排程 "+bo.getScheduleLineId()+orderName);
      List<WmsOrderLine> wmsOrderLineList = new ArrayList<>();
      //根据bo.scheduleLineId，获取batchCode
      WmsScheduleLine scheduleLine = scheduleLineService().queryById(bo.getScheduleLineId());
      bomList.forEach(data -> {
        WmsOrderLine wmsOrderLine = new WmsOrderLine();
        wmsOrderLine.setProductId(data.getProductId());
        wmsOrderLine.setPrice(data.getPurchasePrice());
        wmsOrderLine.setQuantity(Double.parseDouble(data.getQuantity()));
        wmsOrderLine.setMeasureUnit(wmsProductService.queryById(data.getProductId()).getMeasureUnit());
        wmsOrderLine.setBatchCode(scheduleLine.getBatchCode());
        wmsOrderLine.setTotalMoney(data.getPurchasePrice() * Double.parseDouble(data.getQuantity()));
        wmsOrderLine.setCostMoney(data.getPurchasePrice() * Double.parseDouble(data.getQuantity()));
        wmsOrderLineList.add(wmsOrderLine);
      });
      wmsOrder.setLine(wmsOrderLineList);
      wmsOrderService.insertByBo(wmsOrder);
    }

  private Long getWmId(WmsTask bo){
    //通过生产线id获取排程信息，在排程信息中获取生产线id，再通过生产线id获取生产线对应仓库id
    WmsScheduleLine scheduleLine = scheduleLineService().queryById(bo.getScheduleLineId());
    return wmsWorkshopService.queryById(scheduleLine.getWorkshopId()).getWhId();
  }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(WmsTask entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除生产工单
     */
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        LambdaQueryWrapper<WmsTask> lqw = new LambdaQueryWrapper<>();
        lqw.in(WmsTask::getScheduleLineId,ids);
        return baseMapper.delete(lqw) > 0;
    }
}
